import sys
import os
import traceback
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                            QLabel, QPushButton, QLineEdit, QTableWidget, QTableWidgetItem, 
                            QHeaderView, QMessageBox, QProgressBar, QTextEdit, QDialog, 
                            QFileDialog, QStatusBar, QTabWidget, QGroupBox)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QSize
from PyQt5.QtGui import QIcon, QPixmap, QFont

import qq_music_login as login
import qq_music_crawler as crawler

class DownloadThread(QThread):
    """下载线程，避免下载时界面卡顿"""
    progress_signal = pyqtSignal(int, int)  # 下载进度信号
    finished_signal = pyqtSignal(bool, str)  # 下载完成信号

    def __init__(self, url, song_info):
        super().__init__()
        self.url = url
        self.song_info = song_info
        self.filepath = None

    def run(self):
        try:
            # 创建下载目录
            download_dir = "downloads"
            if not os.path.exists(download_dir):
                os.makedirs(download_dir)
            
            # 构建文件名
            import re
            filename = f"{self.song_info['name']} - {self.song_info['singer']}.m4a"
            # 替换文件名中的非法字符
            filename = re.sub(r'[\\/*?:"<>|]', "_", filename)
            self.filepath = os.path.join(download_dir, filename)
            
            import requests
            response = requests.get(self.url, stream=True, timeout=30)
            response.raise_for_status()
            
            total_size = int(response.headers.get('content-length', 0))
            block_size = 1024  # 1 KB
            downloaded = 0
            
            with open(self.filepath, 'wb') as file:
                for data in response.iter_content(block_size):
                    file.write(data)
                    downloaded += len(data)
                    # 发送进度信号
                    self.progress_signal.emit(downloaded, total_size)
            
            # 发送完成信号
            self.finished_signal.emit(True, self.filepath)
        except Exception as e:
            print(f"下载歌曲失败: {e}")
            traceback.print_exc()
            self.finished_signal.emit(False, str(e))

class LoginDialog(QDialog):
    """登录对话框"""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("QQ音乐登录")
        self.setFixedSize(500, 400)
        self.setup_ui()
        
    def setup_ui(self):
        layout = QVBoxLayout()
        
        # 登录说明
        info_label = QLabel("请按照以下步骤登录QQ音乐:")
        info_label.setAlignment(Qt.AlignCenter)
        info_label.setFont(QFont("Arial", 12, QFont.Bold))
        layout.addWidget(info_label)
        
        # 步骤说明
        steps_text = QTextEdit()
        steps_text.setReadOnly(True)
        steps_text.setHtml("""
        <h3>登录步骤：</h3>
        <ol>
            <li>点击下方的"打开QQ音乐登录页面"按钮</li>
            <li>在打开的浏览器中<b>完成QQ音乐登录</b></li>
            <li>登录成功后，按<b>F12</b>打开开发者工具</li>
            <li>在开发者工具中，选择<b>"网络"</b>或<b>"Network"</b>标签</li>
            <li>刷新页面（按F5）</li>
            <li>在网络请求列表中找到任意一个请求（比如fcg-bin开头的请求）</li>
            <li>右键点击请求，选择"复制"，然后选择以下任一选项：
                <ul>
                    <li><b>复制为cURL(bash)</b></li>
                    <li>复制为cURL(cmd)</li>
                    <li>复制为cURL(PowerShell)</li>
                    <li>或任何包含"cURL"的选项</li>
                </ul>
            </li>
            <li>将复制的内容<b>完整粘贴</b>到下方输入框中</li>
        </ol>
        
        <h3>常见问题：</h3>
        <ul>
            <li><b>如果登录失败</b>，请确保：
                <ol>
                    <li>已在浏览器中成功登录QQ音乐</li>
                    <li>复制的是完整的cURL命令（通常很长）</li>
                    <li>命令中包含了cookie信息</li>
                </ol>
            </li>
            <li>如果使用Chrome浏览器，可以在Network标签中筛选XHR请求，找到带有cookie的请求</li>
            <li>确保在复制cURL命令前已经完成了QQ音乐的登录</li>
        </ul>
        """)
        layout.addWidget(steps_text)
        
        # 打开登录页面按钮
        open_btn = QPushButton("打开QQ音乐登录页面")
        open_btn.clicked.connect(login.open_login_page)
        layout.addWidget(open_btn)
        
        # cURL输入框
        layout.addWidget(QLabel("请粘贴复制的cURL命令:"))
        self.curl_input = QTextEdit()
        self.curl_input.setPlaceholderText("在此粘贴完整的cURL命令...\n命令通常以 curl 'https://...' 开头，包含多个 -H 参数")
        layout.addWidget(self.curl_input)
        
        # 按钮布局
        btn_layout = QHBoxLayout()
        
        # 测试按钮
        test_btn = QPushButton("测试命令")
        test_btn.setToolTip("测试是否能从cURL命令中提取cookie")
        test_btn.clicked.connect(self.test_curl)
        btn_layout.addWidget(test_btn)
        
        # 登录按钮
        login_btn = QPushButton("登录")
        login_btn.clicked.connect(self.process_login)
        btn_layout.addWidget(login_btn)
        
        layout.addLayout(btn_layout)
        
        self.setLayout(layout)
    
    def test_curl(self):
        """测试cURL命令是否能成功提取cookie"""
        curl_command = self.curl_input.toPlainText().strip()
        if not curl_command:
            QMessageBox.warning(self, "输入错误", "请粘贴cURL命令")
            return
        
        # 从cURL命令中提取cookie
        cookies = login.extract_cookies_from_curl(curl_command)
        if not cookies:
            QMessageBox.warning(self, "提取失败", "无法从cURL命令中提取cookie，请确保复制了完整的命令")
            return
        
        # 显示提取结果
        cookie_count = len(cookies)
        important_cookies = []
        
        # 检查一些重要的cookie
        for key in ['uin', 'skey', 'p_uin', 'p_skey', 'wxuin', 'wxsid', 'qm_keyst']:
            if key in cookies:
                # 只显示部分值，保护隐私
                value = cookies[key]
                if len(value) > 8:
                    masked_value = value[:3] + '****' + value[-3:]
                else:
                    masked_value = value[:1] + '****' + value[-1:] if len(value) > 2 else '****'
                important_cookies.append(f"{key}: {masked_value}")
        
        # 构建结果消息
        result_message = f"成功提取 {cookie_count} 个cookie!\n\n"
        
        if important_cookies:
            result_message += "找到以下重要cookie:\n" + "\n".join(important_cookies) + "\n\n"
        else:
            result_message += "未找到重要的登录cookie，可能无法成功登录。\n\n"
        
        result_message += "点击\"登录\"按钮尝试使用这些cookie登录。"
        
        QMessageBox.information(self, "测试结果", result_message)
    
    def process_login(self):
        curl_command = self.curl_input.toPlainText().strip()
        if not curl_command:
            QMessageBox.warning(self, "输入错误", "请粘贴cURL命令")
            return
        
        cookies = login.extract_cookies_from_curl(curl_command)
        if cookies:
            # 保存cookie
            if login.save_cookies(cookies):
                # 获取用户信息
                user_info = login.get_user_info(cookies)
                if user_info:
                    success_msg = f"QQ音乐登录成功！\n\n用户名: {user_info['nickname']}"
                    if user_info['is_vip']:
                        success_msg += "\n账号类型: VIP会员"
                    else:
                        success_msg += "\n账号类型: 普通用户"
                    QMessageBox.information(self, "登录成功", success_msg)
                else:
                    QMessageBox.information(self, "登录成功", "QQ音乐登录成功！")
                
                self.accept()  # 关闭对话框并返回接受结果
            else:
                QMessageBox.warning(self, "保存失败", "登录信息保存失败")
        else:
            QMessageBox.warning(self, "提取失败", "无法从cURL命令中提取登录信息，请确保复制了完整的命令")

class QQMusicApp(QMainWindow):
    """QQ音乐主应用窗口"""
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QQ音乐下载器")
        self.setMinimumSize(800, 600)
        
        # 初始化变量
        self.cookies = None
        self.songs = []
        self.current_song = None
        self.download_thread = None
        
        # 加载登录信息
        self.load_login_info()
        
        # 设置界面
        self.setup_ui()
    
    def load_login_info(self):
        """加载登录信息"""
        self.cookies = login.load_cookies()
        if self.cookies and not login.check_login_status(self.cookies):
            # 登录已过期
            self.cookies = None
            login.logout()
    
    def setup_ui(self):
        """设置界面"""
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        main_layout = QVBoxLayout(central_widget)
        
        # 顶部区域 - 登录状态和搜索
        top_layout = QHBoxLayout()
        
        # 登录状态区域
        self.login_group = QGroupBox("登录状态")
        login_layout = QVBoxLayout()
        
        # 登录状态标签
        self.login_status_label = QLabel("未登录")
        login_layout.addWidget(self.login_status_label)
        
        # 登录/退出按钮
        self.login_btn = QPushButton("登录")
        self.login_btn.clicked.connect(self.show_login_dialog)
        login_layout.addWidget(self.login_btn)
        
        self.login_group.setLayout(login_layout)
        top_layout.addWidget(self.login_group)
        
        # 搜索区域
        search_group = QGroupBox("搜索歌曲")
        search_layout = QHBoxLayout()
        
        self.search_input = QLineEdit()
        self.search_input.setPlaceholderText("输入歌曲名或歌手名")
        self.search_input.returnPressed.connect(self.search_music)
        search_layout.addWidget(self.search_input)
        
        search_btn = QPushButton("搜索")
        search_btn.clicked.connect(self.search_music)
        search_layout.addWidget(search_btn)
        
        search_group.setLayout(search_layout)
        top_layout.addWidget(search_group)
        
        main_layout.addLayout(top_layout)
        
        # 搜索结果表格
        self.result_table = QTableWidget(0, 5)  # 5列：序号、歌曲名、歌手、专辑、时长
        self.result_table.setHorizontalHeaderLabels(["序号", "歌曲名", "歌手", "专辑", "时长"])
        self.result_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.result_table.setEditTriggers(QTableWidget.NoEditTriggers)  # 不可编辑
        self.result_table.setSelectionBehavior(QTableWidget.SelectRows)  # 选择整行
        self.result_table.setSelectionMode(QTableWidget.SingleSelection)  # 单选
        self.result_table.doubleClicked.connect(self.download_selected)
        main_layout.addWidget(self.result_table)
        
        # 操作按钮区域
        btn_layout = QHBoxLayout()
        
        self.download_btn = QPushButton("下载选中歌曲")
        self.download_btn.clicked.connect(self.download_selected)
        self.download_btn.setEnabled(False)
        btn_layout.addWidget(self.download_btn)
        
        self.play_btn = QPushButton("播放选中歌曲")
        self.play_btn.clicked.connect(self.play_selected)
        self.play_btn.setEnabled(False)
        btn_layout.addWidget(self.play_btn)
        
        main_layout.addLayout(btn_layout)
        
        # 下载进度条
        self.progress_group = QGroupBox("下载进度")
        progress_layout = QVBoxLayout()
        
        self.progress_label = QLabel("准备下载...")
        progress_layout.addWidget(self.progress_label)
        
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setValue(0)
        progress_layout.addWidget(self.progress_bar)
        
        self.progress_group.setLayout(progress_layout)
        self.progress_group.setVisible(False)
        main_layout.addWidget(self.progress_group)
        
        # 状态栏
        self.statusBar = QStatusBar()
        self.setStatusBar(self.statusBar)
        self.statusBar.showMessage("准备就绪")
        
        # 更新登录状态显示
        self.update_login_status()
    
    def update_login_status(self):
        """更新登录状态显示"""
        if self.cookies:
            user_info = login.get_user_info(self.cookies)
            if user_info:
                self.login_status_label.setText(f"已登录: {user_info['nickname']}")
                self.login_status_label.setStyleSheet("color: green;")
                self.login_btn.setText("退出登录")
                self.login_btn.clicked.disconnect()
                self.login_btn.clicked.connect(self.logout)
                self.statusBar.showMessage(f"已登录: {user_info['nickname']}" + (" (VIP用户)" if user_info['is_vip'] else ""))
                return
        
        # 未登录或获取用户信息失败
        self.login_status_label.setText("未登录")
        self.login_status_label.setStyleSheet("color: red;")
        self.login_btn.setText("登录")
        try:
            self.login_btn.clicked.disconnect()
        except:
            pass
        self.login_btn.clicked.connect(self.show_login_dialog)
        self.statusBar.showMessage("未登录")
    
    def show_login_dialog(self):
        """显示登录对话框"""
        dialog = LoginDialog(self)
        if dialog.exec_():
            # 登录成功，重新加载登录信息
            self.load_login_info()
            self.update_login_status()
    
    def logout(self):
        """退出登录"""
        if login.logout():
            self.cookies = None
            self.update_login_status()
            QMessageBox.information(self, "退出成功", "已退出登录")
    
    def search_music(self):
        """搜索音乐"""
        keyword = self.search_input.text().strip()
        if not keyword:
            QMessageBox.warning(self, "输入错误", "请输入搜索关键词")
            return
        
        self.statusBar.showMessage(f"正在搜索: {keyword}...")
        
        # 清空表格
        self.result_table.setRowCount(0)
        self.songs = []
        self.download_btn.setEnabled(False)
        self.play_btn.setEnabled(False)
        
        # 搜索歌曲
        try:
            self.songs = crawler.get_qq_music_info(keyword, self.cookies)
            
            if not self.songs:
                self.statusBar.showMessage(f"未找到相关歌曲: {keyword}")
                return
            
            # 显示搜索结果
            self.result_table.setRowCount(len(self.songs))
            for i, song in enumerate(self.songs):
                # 序号
                self.result_table.setItem(i, 0, QTableWidgetItem(str(i + 1)))
                # 歌曲名
                self.result_table.setItem(i, 1, QTableWidgetItem(song['name']))
                # 歌手
                self.result_table.setItem(i, 2, QTableWidgetItem(song['singer']))
                # 专辑
                self.result_table.setItem(i, 3, QTableWidgetItem(song['album']))
                # 时长
                minutes = song['time'] // 60
                seconds = song['time'] % 60
                time_str = f"{minutes}:{seconds:02d}"
                self.result_table.setItem(i, 4, QTableWidgetItem(time_str))
            
            self.statusBar.showMessage(f"找到 {len(self.songs)} 首相关歌曲")
            
            # 启用下载按钮
            self.result_table.selectRow(0)  # 默认选中第一行
            self.download_btn.setEnabled(True)
            
        except Exception as e:
            self.statusBar.showMessage(f"搜索失败: {str(e)}")
            traceback.print_exc()
    
    def download_selected(self):
        """下载选中的歌曲"""
        selected_rows = self.result_table.selectedIndexes()
        if not selected_rows:
            QMessageBox.warning(self, "选择错误", "请选择要下载的歌曲")
            return
        
        row = selected_rows[0].row()
        self.current_song = self.songs[row]
        
        self.statusBar.showMessage(f"正在获取歌曲URL: {self.current_song['name']}...")
        
        # 获取歌曲URL
        try:
            song_url = crawler.get_song_url(self.current_song['mid'], self.cookies)
            
            if not song_url:
                self.statusBar.showMessage(f"无法获取歌曲URL: {self.current_song['name']}")
                QMessageBox.warning(self, "下载失败", f"无法获取歌曲URL: {self.current_song['name']}")
                return
            
            # 显示进度条
            self.progress_group.setVisible(True)
            self.progress_label.setText(f"正在下载: {self.current_song['name']} - {self.current_song['singer']}")
            self.progress_bar.setValue(0)
            
            # 创建下载线程
            self.download_thread = DownloadThread(song_url, self.current_song)
            self.download_thread.progress_signal.connect(self.update_progress)
            self.download_thread.finished_signal.connect(self.download_finished)
            self.download_thread.start()
            
        except Exception as e:
            self.statusBar.showMessage(f"下载失败: {str(e)}")
            traceback.print_exc()
    
    def update_progress(self, downloaded, total):
        """更新下载进度"""
        if total > 0:
            percent = int(downloaded * 100 / total)
            self.progress_bar.setValue(percent)
            self.progress_label.setText(f"正在下载: {self.current_song['name']} - {self.current_song['singer']} ({percent}%)")
    
    def download_finished(self, success, result):
        """下载完成回调"""
        if success:
            self.statusBar.showMessage(f"下载完成: {result}")
            self.progress_label.setText(f"下载完成: {self.current_song['name']} - {self.current_song['singer']}")
            self.progress_bar.setValue(100)
            
            # 启用播放按钮
            self.play_btn.setEnabled(True)
            
            # 询问是否播放
            reply = QMessageBox.question(self, "下载完成", 
                                        f"歌曲 {self.current_song['name']} 下载完成，是否立即播放？",
                                        QMessageBox.Yes | QMessageBox.No)
            if reply == QMessageBox.Yes:
                self.play_music(result)
        else:
            self.statusBar.showMessage(f"下载失败: {result}")
            self.progress_label.setText(f"下载失败: {self.current_song['name']} - {self.current_song['singer']}")
            QMessageBox.warning(self, "下载失败", f"下载歌曲失败: {result}")
    
    def play_selected(self):
        """播放选中的歌曲"""
        selected_rows = self.result_table.selectedIndexes()
        if not selected_rows:
            QMessageBox.warning(self, "选择错误", "请选择要播放的歌曲")
            return
        
        row = selected_rows[0].row()
        song = self.songs[row]
        
        # 检查是否已下载
        download_dir = "downloads"
        filename = f"{song['name']} - {song['singer']}.m4a"
        import re
        filename = re.sub(r'[\\/*?:"<>|]', "_", filename)
        filepath = os.path.join(download_dir, filename)
        
        if os.path.exists(filepath):
            # 已下载，直接播放
            self.play_music(filepath)
        else:
            # 未下载，先下载再播放
            reply = QMessageBox.question(self, "播放歌曲", 
                                        f"歌曲 {song['name']} 尚未下载，是否先下载？",
                                        QMessageBox.Yes | QMessageBox.No)
            if reply == QMessageBox.Yes:
                self.download_selected()
    
    def play_music(self, filepath):
        """播放音乐文件"""
        try:
            self.statusBar.showMessage(f"正在播放: {os.path.basename(filepath)}")
            
            # 使用系统默认程序打开音乐文件
            if sys.platform == "win32":
                os.startfile(filepath)
            elif sys.platform == "darwin":  # macOS
                os.system(f"open '{filepath}'")
            else:  # linux
                os.system(f"xdg-open '{filepath}'")
        except Exception as e:
            self.statusBar.showMessage(f"播放失败: {str(e)}")
            QMessageBox.warning(self, "播放失败", f"播放歌曲失败: {str(e)}")

def main():
    app = QApplication(sys.argv)
    window = QQMusicApp()
    window.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()